/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.skatiger.jrove.util;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.skatiger.jrove.JroveContext;
import org.skatiger.jrove.ViewContext;
import org.skatiger.jrove.component.UIComponent;
import org.skatiger.jrove.component.UIViewRoot;

public final class ComponentSupport {
    public final static String MARK_DELETED = "~jrove.MARK_DELETED~";
    public final static String MARK_CREATED = "~jrove.MARK_ID~";
    public static final String NAMED_COMPONENT = "~jrove.NamedComponent~";
    /**
     * Used in conjunction with markForDeletion where any UIComponent marked
     * will be removed.
     * 
     * @param c
     *            UIComponent to finalize
     */
    public static final void finalizeForDeletion(UIComponent c) {
        // remove any existing marks of deletion
        c.getAttributes().remove(MARK_DELETED);

        // finally remove any children marked as deleted
        int sz = c.getChildCount();
        if (sz > 0) {
            UIComponent cc = null;
            List<UIComponent> cl = c.getChildren();
            while (--sz >= 0) {
                cc = cl.get(sz);
                if (cc.getAttributes().containsKey(MARK_DELETED)) {
                    cl.remove(sz);
                }
            }
        }

        // remove any facets marked as deleted
        if (c.getFacets().size() > 0) {
            Collection<UIComponent> col = c.getFacets().values();
            UIComponent fc;
            for (Iterator<UIComponent> itr = col.iterator(); itr.hasNext();) {
                fc = (UIComponent) itr.next();
                if (fc.getAttributes().containsKey(MARK_DELETED)) {
                    itr.remove();
                }
            }
        }
    }

    /**
     * A lighter-weight version of UIComponent's findChild.
     * 
     * @param parent
     *            parent to start searching from
     * @param id
     *            to match to
     * @return UIComponent found or null
     */
    public static final UIComponent findChild(UIComponent parent, String id) {
        int sz = parent.getChildCount();
        if (sz > 0) {
            UIComponent c = null;
            List<UIComponent> cl = parent.getChildren();
            while (--sz >= 0) {
                c = cl.get(sz);
                if (id.equals(c.getId())) {
                    return c;
                }
            }
        }
        return null;
    }

    /**
     * By TagId, find Child
     * 
     * @param parent
     * @param id
     * @return
     */
    public static final UIComponent findChildByTagId(UIComponent parent,
            String id) {
        Iterator<UIComponent> itr = parent.getFacetsAndChildren();
        UIComponent c = null;
        String cid = null;
        while (itr.hasNext()) {
            c = (UIComponent) itr.next();
            cid = (String) c.getAttributes().get(MARK_CREATED);
            if (id.equals(cid)) {
                return c;
            }
        }
        // int sz = parent.getChildCount();
        // if (sz > 0) {
        // UIComponent c = null;
        // List cl = parent.getChildren();
        // String cid = null;
        // while (--sz >= 0) {
        // c = (UIComponent) cl.get(sz);
        // cid = (String) c.getAttributes().get(MARK_CREATED);
        // if (id.equals(cid)) {
        // return c;
        // }
        // }
        // }
        return null;
    }

    /**
     * Tries to walk up the parent to find the UIViewRoot, if not found, then go
     * to FaceletContext's FacesContext for the view root.
     * 
     * @param ctx
     *            FaceletContext
     * @param parent
     *            UIComponent to search from
     * @return UIViewRoot instance for this evaluation
     */
    public static UIViewRoot getViewRoot(JroveContext ctx, UIComponent parent) {
        return getViewRoot(ctx.getViewContext(), parent);
    }

    /**
     * Tries to walk up the parent to find the UIViewRoot, if not found, then go
     * to FaceletContext's FacesContext for the view root.
     * 
     * @param ctx
     *            FaceletContext
     * @param parent
     *            UIComponent to search from
     * @return UIViewRoot instance for this evaluation
     */
    public static UIViewRoot getViewRoot(ViewContext context, UIComponent parent) {
        UIComponent c = parent;
        do {
            if (c instanceof UIViewRoot) {
                return (UIViewRoot) c;
            } else {
                c = c.getParent();
            }
        } while (c != null);

        return context.getViewRoot();
    }

    /**
     * Determine if the passed component is not null and if it's new to the
     * tree. This operation can be used for determining if attributes should be
     * wired to the component.
     * 
     * @param component
     *            the component you wish to modify
     * @return true if it's new
     */
    public final static boolean isNew(UIComponent component) {
        return component != null && component.getParent() == null;
    }

    /**
     * Marks all direct children and Facets with an attribute for deletion.
     * 
     * @see #finalizeForDeletion(UIComponent)
     * @param c
     *            UIComponent to mark
     */
    public static final void markForDeletion(UIComponent c) {
        // flag this component as deleted
        c.getAttributes().put(MARK_DELETED, Boolean.TRUE);

        // mark all children to be deleted
        int sz = c.getChildCount();
        if (sz > 0) {
            UIComponent cc = null;
            List<UIComponent> cl = c.getChildren();
            while (--sz >= 0) {
                cc = cl.get(sz);
                if (cc.getAttributes().containsKey(MARK_CREATED)) {
                    cc.getAttributes().put(MARK_DELETED, Boolean.TRUE);
                }
            }
        }

        // mark all facets to be deleted
        if (c.getFacets().size() > 0) {
            Collection<UIComponent> col = c.getFacets().values();
            UIComponent fc;
            for (Iterator<UIComponent> itr = col.iterator(); itr.hasNext();) {
                fc = (UIComponent) itr.next();
                if (fc.getAttributes().containsKey(MARK_CREATED)) {
                    fc.getAttributes().put(MARK_DELETED, Boolean.TRUE);
                }
            }
        }
    }
}
